package JBD.Projet_Audacity;

import java.io.*;
import java.util.ArrayList;


public class Piste{
	private File fichier;
	private String filename;
	private int[] entete;
	private int tailleEnTete, tailledonnee, nbcanal, fechant, nbechantillon, nbBitperSample, nboctet, duree, gain=1;
	private long tailleFichier;
	double periode;
	private boolean signe = true; 
	public ArrayList<Canal> mesCanaux;

	
	
/**************************** Constructeurs de Piste ********************************/
	
	
	//Récupération du fichier dans un FileInputStream, puis de l'en-tête dans un tableau de 44 octets
	//Vérification si le fichier est un Wav, puis calcul des informations du fichier
	
	Piste(){
		fechant = 32000;
		nbcanal=2;
		nboctet = 2;
		mesCanaux = new ArrayList<Canal>(nbcanal);
		for (int i=0 ; i < nbcanal ; i++)
		    mesCanaux.add(new Canal());
	}
	
	Piste(String file){
		filename = file;
		fechant = 32000;
		nbcanal=1;
		nboctet = 2;
		mesCanaux = new ArrayList<Canal>(nbcanal);
		for (int i=0 ; i < nbcanal ; i++)
		    mesCanaux.add(new Canal());
	}
	
	/*Piste(int freq, int nbcan, int nboctet1){
		fechant = freq;
		nbcanal = nbcan;
		nboctet = nboctet1;
		mesCanaux = new ArrayList<Canal>(nbcanal);
		for (int i=0 ; i < nbcanal ; i++)
		    mesCanaux.add(new Canal());
		try {
			lecture = new FileInputStream(fichier);
		} catch (FileNotFoundException e) {
				e.printStackTrace();
		}
			
	}
*/

/****************************** PISTE WAV ************************************/	
		public Piste(String filename1, int wave){
			filename = filename1;
			fichier = new File(filename);
			recupererEntete();
			if(estWav()){
				initWav();
				afficheInformation();
			}
			
			int echantillonCour;
			int numCanalCour = 0;  
			byte[] buffer;
			byte[] entetebis = new byte[44];
			int n;
			try{
			    //met le fichier dans un fichier "lisible" (en tant que fichier son)
			    InputStream lect = new FileInputStream(fichier);
			    //on instancie une nouvelle piste a partir des informations du fichier qu'on lit
				mesCanaux = new ArrayList<Canal>(nbcanal);
				for (int i=0 ; i < nbcanal ; i++)
				    mesCanaux.add(new Canal());
			    //on crée un buffer avec une taille = nombre d'octet par echantillon
			    buffer = new byte[nboctet];
			    //On lit le nombre d'échantillons contenu dans Buffer
			    n = lect.read(entetebis);
/*
			    while (n>0){
					    //transforme les octets d'un échantillon en un int
						echantillonCour = creerEchantillon(buffer, nboctet);
						//ajoute l'échantillon tranformé en int au canal
						mesCanaux.get(numCanalCour).addEchant(echantillonCour);
						//passe au canal suivant (si mono, stéréo,...)
						numCanalCour = (numCanalCour + 1) % nbcanal;
						//passe a l'échantillon suivant)
						n = lect.read(buffer,0,nboctet);
			    }
*/
			    
			    while (n>0){
					echantillonCour = creerEchantillon(buffer, nboctet);
					mesCanaux.get(numCanalCour).addEchant(echantillonCour);
					numCanalCour = (numCanalCour + 1) % nbcanal;
					n = lect.read(buffer,0,nboctet);
				    }
				}catch(IOException e){}
				System.out.println("\nnb Echantillons (WAV) : " + mesCanaux.get(0).getnbEchant());
		    }
		
		
/****************************** PISTE RAW ************************************/
	
		public Piste(String filename1,int nbcanaux, int frequence, int nboctet1){
			filename = filename1;
			fechant = frequence;
			nbcanal = nbcanaux;
			nboctet = nboctet1;
			mesCanaux = new ArrayList<Canal>(nbcanal);
			for (int i=0 ; i < nbcanal ; i++)
			    mesCanaux.add(new Canal());
			int echantillonCour;
			int numCanalCour = 0;  
			byte[] buffer;
			int n=1;
			try{
				//r�cup�re le fichier
			    File fichierlu = new File(filename);
			    //met le fichier dans un fichier "lisible" (en tant que fichier son)
			    InputStream lect = new FileInputStream(fichierlu);
			    //on instancie une nouvelle piste a partir des informations du fichier qu'on lit
			    //retour = new Piste(frequence, nbcanaux, nboctet);
			    //on crée un buffer avec une taille = nombre d'octet par echantillon
			    buffer = new byte[nboctet];
			    while (n>0){
				    //transforme les octets d'un échantillon en un int
					echantillonCour = creerEchantillon(buffer, nboctet);
					//ajoute l'échantillon tranformé en int au canal
					mesCanaux.get(numCanalCour).addEchant(echantillonCour);
					//passe au canal suivant (si mono, stéréo,...)
					numCanalCour = (numCanalCour + 1) % nbcanaux;
					//passe a l'échantillon suivant)
					n = lect.read(buffer,0,nboctet);
			    }
			    lect.close();
			    tailleFichier = fichierlu.length();
			}catch(IOException e){}
			System.out.println("nb Echantillons : " + mesCanaux.get(0).getnbEchant());
		    }

/**************************** Sauvegarde WAV *************************************************/
		 public void savetoWav(String nomFichier){
			 //nomFichier = "lesEtoiles.wav";
			 
			 try{ 
				 FileOutputStream sortie = new FileOutputStream(nomFichier);
				 int nbech = getnbEch();
				 int echcour;
				 int canalcour = 0;
				 int i = 0;
				 byte [] buffer;
				 int resolution = getnbOctet();
				 //On met tous les canaux de p � 0
				 initLecture();
				 sortie.write(creerEntete());
				 while (i<nbech){
						echcour = getCanal(canalcour).getmesEchantillons(i);
						buffer = echantillonToByte(echcour,resolution );
						canalcour = (canalcour + 1) % nbcanal;
						sortie.write(buffer, 0, resolution);
						if(canalcour==nbcanal-1)
							i++;
					    }
				 sortie.close();
				 }catch(Exception e){
					 e.printStackTrace();
					 System.out.println(e);
					 }
			 System.out.println("Sauvegarde : OK");
			 }		 
	 
/**************************** Sauvegarde RAW *************************************************/
	 public void savetoRaw(String nomFichier){
		 //nomFichier = "son.raw";
		 
		 try{ 
			 FileOutputStream sortie = new FileOutputStream(nomFichier);
			 int nbech = getnbEch();
			 int echcour;
			 int canalcour = 0;
			 int i = 0;
			 byte [] buffer;
			 int resolution = getnbOctet();
			 //On met tous les canaux de p � 0
			 initLecture();
			 while (i<nbech){
					echcour = getCanal(canalcour).getmesEchantillons(i);
					buffer = echantillonToByte(echcour,resolution );
					canalcour = (canalcour + 1) % nbcanal;
					sortie.write(buffer, 0, resolution);
					if(canalcour==nbcanal-1)
						i++;
				    }
			 
			 
			 System.out.println("i : " + i + " nb echant : "+ nbech);
			 sortie.close();
			 }catch(Exception e){
				 e.printStackTrace();
				 System.out.println(e);
				 }
		 System.out.println("Sauvegarde : OK");
		 }
	 
/************************************ WAV OU RAW ***********************************************/	 
//Verifier si le fichier est un "wav" (on regarde si on a bien RIFF et WAVE)
	public boolean estWav(){
		String wav = ".wav";
		String test;
		test = filename.substring(filename.length()-4, filename.length());
		
		//if((entete[0]==82 & entete[1]==73 & entete[2] == 70 & entete[3] == 70) & (entete[8]==87 & entete[9]==65 & entete[10] == 86 & entete[11] == 69))
		if(test.equals(wav))	
			return true;
		else{
			return false;
		}
	}

	public boolean estRaw(){
		String raw = ".raw";
		String test;
		test = filename.substring(filename.length()-4, filename.length());
		if(test.equals(raw)){
			return true;
		}
		return false;
	}
	
/************************************  CREATION WAV ***********************************************/	
	
	//calcul des differentes information a propos du fichier "wav"
	private void initWav(){
		//taille totale
		tailleEnTete = entete[7]<< 24 | entete[6]<< 16 | entete[5]<< 8 | entete[4];
		tailleFichier = fichier.length();
		//System.out.println("taille fichier : " + tailletotale + " taille reelle : " +tailletotale2);
		
		//Taille des donnees
		tailledonnee = (int)tailleFichier - 44;
		
		//Nombre de canaux
		nbcanal = entete[23]<<8 | entete[22];
		
		//Frequence d'echantillonage
		fechant = entete[27]<< 24 | entete[26]<< 16 | entete[25]<< 8 | entete[24];
		
		//Periode
		periode = (double)1/fechant;
		
		//Nombre de bits par echantillon
		nbBitperSample = entete[35] << 8 | entete[34];
		
		//Nombre d'octet par echantillon
		nboctet = nbBitperSample/8;
		
		//Nombre d'octets par seconde
		nbechantillon = nbcanal*(fechant*(nbBitperSample/8));
		
		//Duree du fichier
		duree = tailledonnee/(nbechantillon);		
	}
	
//Affichage des informations du fichier son (wav)
	public void afficheInformation(){	
		//taille totale
		System.out.println("\n*****Informations sur le fichier .wav*****\nTaille totale Ent�te : " + tailleEnTete + " octets\n" + "Taille totale Fichier : " + tailleFichier + " octets");
		
		//Taille des donnees
		System.out.println("Taille des donnees : " + tailledonnee + " octets");
		
		//Nombre de canaux
		if(nbcanal==1)
			System.out.println("Nombre de canaux : "+nbcanal + " (Mono)");
		if(nbcanal==2)
			System.out.println("Nombre de canaux : "+nbcanal + " (Stereo)");
		
		//Frequence d'echantillonage
		System.out.println("Frequence d'echantillonage : " + fechant + " Herz");
		
		//Periode
		//System.out.println("Période : " + periode + " seconde");
		
		//Nombre d'octets par seconde
		//System.out.println("Nombre d'octets par seconde : " + nbechantillon);
		
		//Nombre de bit par Echantillon
		//System.out.println("Nombre de bit par echantillon: " + nbBitperSample);
		
		//Nombre d'octet par Echantillon
		System.out.println("Nombre d'octet par echantillon: " + nboctet);
		
		//Duree du fichier
		System.out.println("Duree : " + duree + "s");
	}

	//R�cup�rer l'en-t�te WAV
	public void recupererEntete(){
		FileInputStream testWav;
		testWav = null;
		entete = new int[44];	
		//On r�cup�re le fichier .wav
		try {
			testWav = new FileInputStream(fichier);
			
		} catch (FileNotFoundException e) {
			System.out.println("Erreur : " + e.getMessage() );
			
		}
		//recuperation des bytes de l'en-tete dans un tableau (entete = 44 octets)
			for(int i=0; i<44;i++){
				try {
					entete[i]= testWav.read();
				} catch (IOException e) {
					e.printStackTrace();
				}
				//System.out.println("entete "+i+" : " + entete[i]);
			}
	}
	
	//Cr�er l'en-t�te WAV
	public byte[] creerEntete(){
		byte finentete[] = new byte[44];
		byte[] temp2 = new byte[2];
		byte[] temp4 = new byte[4];
		//RIFF
		finentete[0]='R';
		finentete[1]='I';
		finentete[2]='F';
		finentete[3]='F';
	
		//Taille totale - 8
		tailleEnTete = (int)tailleFichier+44-8;
		temp4= echantillonToByte(tailleEnTete, 4);
		finentete[4]=temp4[0];
		finentete[5]=temp4[1];
		finentete[6]=temp4[2];
		finentete[7]=temp4[3];
		
		//WAVE
		finentete[8]='W';
		finentete[9]='A';
		finentete[10]='V';
		finentete[11]='E';
		
		//ID FMT
		finentete[12]='f';
		finentete[13]='m';
		finentete[14]='t';
		finentete[15]=' ';
		
		//Bloc size
		temp4= echantillonToByte(16, 4);
		finentete[16]=temp4[0];
		finentete[17]=temp4[1];
		finentete[18]=temp4[2];
		finentete[19]=temp4[3];
		
		//Format (PCM)
		temp2= echantillonToByte(1, 2);
		finentete[20]=temp2[0];
		finentete[21]=temp2[1];
		
		//Nombre de canaux
		temp2= echantillonToByte(nbcanal, 2);
		finentete[22]=temp2[0];
		finentete[23]=temp2[1];
		
		//Fr�quence d'�chantillonnage
		temp4= echantillonToByte(fechant, 4);
		finentete[24]=temp4[0];
		finentete[25]=temp4[1];
		finentete[26]=temp4[2];
		finentete[27]=temp4[3];
		
		//Octet par seconde
		nbechantillon =nbcanal*fechant*nboctet;
		temp4= echantillonToByte(nbechantillon, 4);
		finentete[28]=temp4[0];
		finentete[29]=temp4[1];
		finentete[30]=temp4[2];
		finentete[31]=temp4[3];
		
		//Octet par bloc (nbcanaux * (nboctet par echantillons))
		temp2= echantillonToByte(nbcanal*nboctet, 2);
		finentete[32]=temp2[0];
		finentete[33]=temp2[1];
		
		//Octets par echantillons
		temp2= echantillonToByte(nboctet*8, 2);
		finentete[34]=temp2[0];
		finentete[35]=temp2[1];
		
		//DATA
		finentete[36]='d';
		finentete[37]='a';
		finentete[38]='t';
		finentete[39]='a';
		
		//Nombre d'octets de donn�es (nombre d'�chantillons * nombre de canaux * octet par secondes)
		temp4= echantillonToByte((int)tailleFichier-44, 4);
		finentete[40]=temp4[0];
		finentete[41]=temp4[1];
		finentete[42]=temp4[2];
		finentete[43]=temp4[3];
			
		return finentete;
	}
	
/************************************ FUSION PISTES ***********************************************/	
	public void fusionPiste(Piste p){
		int nbCanalp = p.getnbCanal(), i;
		System.out.println("mesEchante Fusion : "+ mesCanaux.get(0).getnbEchant());
		//
			//for(int j=nbcanal; j<nbCanalp;j++)
				//mesCanaux.add(new Canal());
		for(i=0; i<nbCanalp;i++){
			if(nbcanal<nbCanalp)
				mesCanaux.add(i, mesCanaux.get(i).fusion(p.mesCanaux.get(i)));
			else
				mesCanaux.set(i, mesCanaux.get(i).fusion(p.mesCanaux.get(i)));
		}
	}
	
	
/****************************** Ajout de Canal ******************************************/
	public void ajoutCanal(){
		mesCanaux.add(new Canal());
		setnbCanal(nbcanal+1);
	}
	
/******************************* Accesseurs ********************************************/
	public File getFile(){
		return fichier;
	}
	public String getFilename(){
		return filename;
	}
	public int getTailleFichier(){
		return (int)tailleFichier;
	}
	public int getTailleD(){
		return tailledonnee;
	}
	
	public int getnbCanal(){
		return nbcanal;
	}
	public int getfEchant(){
		return fechant;
	}
	public boolean getSigne(){
		return signe;
	}
	public int getnbOctet(){
		return nboctet;
	}
	public int getnbEch(){
		return (mesCanaux.get(0).getnbEchant() * mesCanaux.size())/nbcanal;
	    }
	public Canal getCanal(int n){
    	return mesCanaux.get(n);
    }
	public int getGain(){
		return gain;
	}
	public int getDuree(){
		return duree;
	}
	/******************************* Mutateurs **********************************************/
	public void setnbCanal(int newnbCanal){
		nbcanal = newnbCanal;
	}
	
	public void setnbOctet(int newnbOctet){
		nboctet = newnbOctet;
	}
	
	public void setfEchant(int newfEchant){
		fechant = newfEchant;
	}
	
	public void setGain(int g){
		gain = g;
	}
	
	
/******************************** Initialise la lecture *********************************/
	void initLecture(){
		for (Canal c : mesCanaux)
		    c.initLecture();
    }

	
/******************************* Cree un enchantillon => transforme des octets en un int *********************/
	 int creerEchantillon(byte[] buf, int resol){
		int i = resol-1;
		int res = buf[i];
		resol--;
		while (resol > 0){
		    res = res * 256 + buf[i];
		    resol--;
		    i--;
		}
		return res;
	    }

/******************************* Echantillon INT to BYTE *************************************************/
	 byte[] echantillonToByte(int echcour, int resolution){
			int i= 0;
			byte[] res = new byte[resolution];
			while ( i < resolution){
			    res[i] = (byte)(echcour & 0xFF);
			    echcour = echcour >> 8;
			    i++;
			}
			return res;
		    } 
	 
}
